package com.jinke.api.modules.third.shippo.tool;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.jinke.api.common.annotation.Apilog;
import com.jinke.api.common.exception.Asserts;
import com.jinke.api.common.retry.CommonRetryBuilder;
import com.jinke.api.modules.base.constant.EnvironmentConstants;
import com.jinke.api.modules.third.ezeeship.model.request.EstimateRateRequest;
import com.jinke.api.modules.third.shippo.model.constants.ShippoApiConstants;
import com.jinke.api.modules.third.shippo.model.dto.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.compress.utils.Lists;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * @projectName:
 * @title: ShippoRequest
 * @description: shippo请求类
 * @see:
 * @author: hhp
 * @version: 1.0.0
 * @createTime: 2024/8/13 10:26
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ShippoRequest {
    @Value("${shippo.api-prefix}")
    private String apiPrefix;
    @Value("${shippo.test-token}")
    private String testToken;
    @Value("${shippo.prod-token}")
    private String prodToken;
    private final Environment environment;
    private final CommonRetryBuilder retryBuilder;

    /**
     * 盛进国际物流-预估 请求
     */
    private static final String ESTIMATE_RATE ="SHIPPO-预估";
    /**
     * 盛进国际物流-下单 请求
     */
    private static final  String CREATE_LABEL = "SHIPPO-下单";

    /**
     * 下单
     * @param estimateRateRequest
     * @param carrier_accounts
     * @param serveiceleveltoken
     * @return
     */
    @Apilog(requestTypeName = CREATE_LABEL)
    public String createLabel(EstimateRateRequest estimateRateRequest, String carrier_accounts,String serveiceleveltoken) {
        String orderNO = estimateRateRequest.getOrderNO();

        EstimateRateRequest.Address from = estimateRateRequest.getFrom();
        EstimateRateRequest.Address to = estimateRateRequest.getTo();
        List<EstimateRateRequest.Parcel> parcels = estimateRateRequest.getParcels();
        EstimateRateRequest.Parcel parcel = parcels.get(0);
// To Address
        HashMap<String, Object> addressToMap = new HashMap<>();
        addressToMap.put("name", to.getPersonName());
        addressToMap.put("company", to.getCompany());
        addressToMap.put("street1",to.getAddressLine1()+to.getAddressLine2());
        addressToMap.put("city", to.getCity());
        addressToMap.put("state", to.getStateCode());
        addressToMap.put("zip", to.getZipCode());
        addressToMap.put("country",to.getCountryCode());
        addressToMap.put("phone", to.getPhone());
        addressToMap.put("email", to.getEmail());

// From Address
        HashMap<String, Object> addressFromMap = new HashMap<>();
        addressFromMap.put("name", from.getPersonName());
        addressFromMap.put("company", from.getCompany());
        addressFromMap.put("street1",from.getAddressLine1()+to.getAddressLine2());
        addressFromMap.put("city", from.getCity());
        addressFromMap.put("state", from.getStateCode());
        addressFromMap.put("zip", from.getZipCode());
        addressFromMap.put("country",from.getCountryCode());
        addressFromMap.put("phone", from.getPhone());
        addressFromMap.put("email", from.getEmail());
        //自定义字段
        addressFromMap.put("metadata", estimateRateRequest.getExtra().getReference()+ estimateRateRequest.getExtra().getReference());

// Parcel
        HashMap<String, Object> parcelMap = new HashMap<>();
        parcelMap.put("length", parcel.getLength());
        parcelMap.put("width", parcel.getWidth());
        parcelMap.put("height", parcel.getHeight());
        parcelMap.put("distance_unit", parcel.getDistanceUnit());
        parcelMap.put("weight", parcel.getWeight());
        parcelMap.put("mass_unit", parcel.getMassUnit());




// Shipment
        HashMap<String, Object> shipmentMap = new HashMap<>();
        shipmentMap.put("address_to", addressToMap);
        shipmentMap.put("address_from", addressFromMap);
        shipmentMap.put("parcels", parcelMap);
        shipmentMap.put("async", false);
        HashMap<String, Object> customsDeclarationMap = getBGD(estimateRateRequest);
        //跨境报关单
        shipmentMap.put("customs_declaration", customsDeclarationMap);



// Transaction
        HashMap<String, Object> transactionMap = new HashMap<>();
        transactionMap.put("shipment", shipmentMap);
        //从预估中选择后要带过来
        transactionMap.put("servicelevel_token", serveiceleveltoken);
        transactionMap.put("carrier_account", carrier_accounts);
        String param = JSONUtil.toJsonStr(transactionMap);

        log.info("==========shippo下单请求开始================{}，{}", orderNO,param);
        String responseData = sendPostRequest(apiPrefix+ShippoApiConstants.TRANSACTION,param);

        log.info("==========shippo下单请求结束================响应结果:{},{}",orderNO, responseData);
        return responseData;

    }



    @NotNull
    private HashMap<String, Object> getBGD(EstimateRateRequest estimateRateRequest) {
        EstimateRateRequest.LabelExtra extra = estimateRateRequest.getExtra();
       HashMap<String, Object> customsItemMap = new HashMap<>();
//        customsItemMap.put("description", extra.getDescription());
//        customsItemMap.put("quantity", extra.getQuantity());
//        customsItemMap.put("net_weight", "1");
//        customsItemMap.put("mass_unit", extra.getWeightUnit());
//        customsItemMap.put("value_amount", extra.getCustomsDeclaration());
//        //货币单位USD or EUR
//        customsItemMap.put("value_currency", "USD");
//        customsItemMap.put("origin_country", extra.getCountryOfOrigin());
//
//        HashMap<String, Object> customsDeclarationMap = new HashMap<>();
//        customsDeclarationMap.put("contents_type", extra.getContentsType());
//        //这是什么
//        customsDeclarationMap.put("contents_explanation", extra.getDescription());
//        customsDeclarationMap.put("non_delivery_option", extra.getNonDeliveryOption());
//        customsDeclarationMap.put("certify", true);
//        customsDeclarationMap.put("certify_signer", extra.getCertifySigner());
//        customsDeclarationMap.put("items", customsItemMap);
        return null;
    }

    /**
     * 预估
     * @return
     */
    @Apilog(requestTypeName = ESTIMATE_RATE)
    public String estimate(EstimateRateRequest estimateRateRequest, List<String> carrier_accounts) {
        String orderNO = estimateRateRequest.getOrderNO();
        ShippoEstimateDTO dto = getUniEstimateReqDto(estimateRateRequest,carrier_accounts);

        String param = JSONUtil.toJsonStr(dto);
        log.info("==========shippo预估请求开始================{},{}",orderNO,param);
        String responseData = sendPostRequest(new StringBuilder()
                .append(apiPrefix)
                .append(ShippoApiConstants.SHIPMENTS).toString(),param);
        log.info("==========shippo预估响应结果================{},{}",orderNO, responseData);
        return responseData;
    }

    /**
     * 通用参数转成shippo预约参数
     * @param estimateRateRequest
     * @return
     */
    private ShippoEstimateDTO getUniEstimateReqDto(EstimateRateRequest estimateRateRequest,
                                                   List<String> carrier_accounts) {
        EstimateRateRequest.Address from = estimateRateRequest.getFrom();
        EstimateRateRequest.Address to = estimateRateRequest.getTo();
        List<EstimateRateRequest.Parcel> parcels = estimateRateRequest.getParcels();
        ShippoEstimateDTO dto = new ShippoEstimateDTO();
        ShippoEstimateDTO.Address dtoto = new ShippoEstimateDTO.Address();

        ShippoEstimateDTO.Address dtoFrom = new ShippoEstimateDTO.Address();

        dtoFrom.setName(from.getPersonName());
        dtoFrom.setStreet1(from.getAddressLine1());
        dtoFrom.setCity(from.getCity());
        dtoFrom.setState(from.getState());
        dtoFrom.setZip(from.getZipCode());
        dtoFrom.setCountry(from.getCountryCode());
        dtoFrom.setPhone(from.getPhone());
        dtoFrom.setEmail(from.getEmail());

        dtoto.setName(to.getPersonName());
        dtoto.setStreet1(to.getAddressLine1());
        dtoto.setCity(to.getCity());
        dtoto.setState(to.getState());
        dtoto.setZip(to.getZipCode());
        dtoto.setCountry(to.getCountryCode());
        dtoto.setPhone(to.getPhone());
        dtoto.setEmail(to.getEmail());

        dto.setAddress_from(dtoFrom);
        
        dto.setAddress_to(dtoto);
        List<ShippoEstimateDTO.Parcels> parcelsdto = parcels.stream().map(x -> {
            ShippoEstimateDTO.Parcels parcel = new ShippoEstimateDTO.Parcels();
            parcel.setLength(x.getLength());

            parcel.setWidth(x.getWidth());
            parcel.setHeight(x.getHeight());
            parcel.setDistance_unit(x.getDistanceUnit());
            parcel.setWeight(x.getWeight());
            parcel.setMass_unit(x.getMassUnit());


            return parcel;
        }).collect(Collectors.toList());


        dto.setParcels(parcelsdto);
        dto.setCarrier_accounts(carrier_accounts);
        //跨境报关单
        ShippoEstimateDTO.EstimateCustomsDeclaration customsDeclarationMap = getBGDobject(estimateRateRequest);
        dto.setCustoms_declaration(customsDeclarationMap);
        return dto;
    }

    private ShippoEstimateDTO.EstimateCustomsDeclaration getBGDobject(EstimateRateRequest estimateRateRequest) {

        ShippoEstimateDTO.EstimateCustomsDeclaration d=new ShippoEstimateDTO.EstimateCustomsDeclaration();


        EstimateRateRequest.LabelExtra extra = estimateRateRequest.getExtra();



//        d.setContents_type(extra.getContentsType());
//        //这是什么
//        d.setContents_explanation(extra.getDescription());
//        d.setNon_delivery_option(extra.getNonDeliveryOption());
//        d.setCertify(true);
//        d.setCertify_signer(extra.getCertifySigner());
//        ShippoEstimateDTO.customsItem item=new ShippoEstimateDTO.customsItem();
//        item.setDescription( extra.getDescription());
//
//        item.setQuantity( extra.getQuantity());
//        item.setDescription( extra.getDescription());
//        item.setNet_weight( extra.getWeight()+"");
//        item.setMass_unit( extra.getWeightUnit());
//
//        item.setValue_amount( extra.getCustomsDeclaration()+"");
//        item.setValue_currency( "USD");
//        item.setOrigin_country( extra.getCountryOfOrigin());



//        d.setItems(item);

        return d;
    }

    /**
     * shippo获取货运商objectId
     * @return
     */
    public String carrier_accounts() {
        log.info("==========shippo获取货运商objectId请求开始================");
        String responseData = sendGetRequest(new StringBuilder()
                .append(apiPrefix)
                .append(ShippoApiConstants.CARRIER_ACCOUNTS).toString());
        log.info("==========shippo获取货运商objectId请求结束================响应结果:[{}]", responseData);
        return responseData;

    }

    /**
     * 获取面单
     * @param transactionId
     * @return
     */
    public String getSingleLabel(String transactionId) {
        log.info("==========shippo根据transactionId拿到面单请求开始================请求参数:[{}]", transactionId);
        String responseData = sendGetRequest(new StringBuilder()
                .append(apiPrefix)
                .append(ShippoApiConstants.TRANSACTION)
                .append(transactionId).toString());
        log.info("==========shippo根据transactionId拿到面单请求结束================响应结果:[{}]", responseData);
        return responseData;
    }

    /**
     * 退款取消
     * @param shippoRefundReqDTO
     * @param orderNo
     * @return
     */
    @Apilog(requestTypeName = "shippo-取消")
    public String refund(ShippoRefundReqDTO shippoRefundReqDTO, String orderNo) {
        String param = JSONObject.toJSONString(shippoRefundReqDTO);
        log.info("==========shippo通过objectId取消请求开始============={}===请求参数:[{}]",orderNo, shippoRefundReqDTO);
        String responseData = sendPostRequest(apiPrefix + ShippoApiConstants.REFUNDS, param);
        log.info("==========shippo通过objectId取消请求结束============={}===响应结果:[{}]",orderNo, responseData);
        return responseData;
    }

    /**
     * 退款取消
     * @param refundId
     * @return
     */
    public String getSingleRefund(String refundId) {
        log.info("==========shippo根据refundId拿到refund请求开始================请求参数:[{}]", refundId);
        String responseData = sendGetRequest(new StringBuilder()
                .append(apiPrefix)
                .append(ShippoApiConstants.GET_REFUND)
                .append(refundId).toString());
        log.info("==========shippo根据refundId拿到refund请求结束================响应结果:[{}]", responseData);
        return responseData;
    }

    /**
     * 查状态
     * @param carrier
     * @param trackingNumber
     * @return
     */
    public String getSingleTrack(String carrier, String trackingNumber) {
        log.info("==========shippo根据carrier, trackingNumber拿到tracking status请求开始================请求参数carrier:[{}], trackingNumber:[{}]", carrier, trackingNumber);
        String responseData = sendGetRequest(new StringBuilder()
                .append(apiPrefix)
                .append(ShippoApiConstants.GET_TRACK)
                .append(carrier)
                .append(trackingNumber).toString());
        log.info("==========shippo根据carrier, trackingNumber拿到tracking status请求结束================响应结果:[{}]", responseData);
        return responseData;
    }

    /**
     * 地址校验
     * @param shippoAddressReqDto
     * @return
     */
    public String createAddressValidation(ShippoAddressReqDto shippoAddressReqDto) {
        log.info("==========shippo Create a new address拿到validation_results请求开始================请求参数:[{}]", shippoAddressReqDto);
        String responseData = sendPostRequest(apiPrefix + ShippoApiConstants.ADDRESSES,
                JSONObject.toJSONString(shippoAddressReqDto));
        log.info("==========shippo Create a new address拿到validation_results请求结束================响应结果:[{}]", responseData);
        return responseData;
    }

    /**
     * 创建报关单
     * @param request
     * @return
     */
    public String customsDeclaration(EstimateRateRequest request) {

        EstimateRateRequest.LabelExtra extra = request.getExtra();

//
//        ShippoCreateDeclarationsDTO.DeclarationItem declarationItem = new ShippoCreateDeclarationsDTO.DeclarationItem().setDescription(extra.getDescription())
//                .setMassUnit(extra.getWeightUnit())
//                .setNetWeight(extra.getWeight()).setOriginCountry(extra.getCountryOfOrigin()).setQuantity(extra.getQuantity())
//                .setValueAmount(extra.getCustomsDeclaration()).setValueCurrency("USD");
//        List<ShippoCreateDeclarationsDTO.DeclarationItem> items = Lists.newArrayList();
//        items.add(declarationItem);
//        ShippoCreateDeclarationsDTO shippoCreateDeclarationsDTO = new ShippoCreateDeclarationsDTO()
//                .setCertify(true).setCertifySigner(extra.getCertifySigner()).setContentsType(extra.getContentsType())
//                .setItems(items).setNonDeliveryOption(extra.getNonDeliveryOption());


        String param =null;
//                JSONObject.toJSONString(null);
        log.info("==========shippo 海关申报单请求开始================请求参数:[{}]", param);
        String responseData = sendPostRequest(apiPrefix + ShippoApiConstants.CUSTOMS_DECLARATIONS,param);
        log.info("==========shippo 海关申报单请求结束================响应结果:[{}]", responseData);
        return responseData;
    }

    /**
     * 申报
     * @param estimateRateRequest
     * @return
     */
    public String declaration(EstimateRateRequest estimateRateRequest) {
//        HashMap<String, Object> customsItemMap = new HashMap<>();
////ShippoLableCreateDTO.CustomsDeclaration
//        EstimateRateRequest.LabelExtra extra = estimateRateRequest.getExtra();
//        List<CustomsDeclaration> customsDeclarations =
//        CustomsDeclaration customsDeclaration1 = customsDeclarations.get(0);
//        List<EstimateRateRequest.CustomsDeclarationItem> items = customsDeclaration1.getItems();
//        EstimateRateRequest.CustomsDeclarationItem customsDeclarationItem = items.get(0);
//        customsItemMap.put("description", customsDeclarationItem.getDescription());
//        customsItemMap.put("quantity", customsDeclarationItem.getQuantity());
//        customsItemMap.put("net_weight", 2);
//        customsItemMap.put("mass_unit", "lb");
//        customsItemMap.put("value_amount", "200");
//        customsItemMap.put("value_currency", "USD");
//        customsItemMap.put("origin_country",extra.);
//
//        HashMap<String, Object> customsDeclarationMap = new HashMap<String, Object>();
//        customsDeclarationMap.put("contents_type", "MERCHANDISE");
//        customsDeclarationMap.put("contents_explanation", "T-Shirt purchase");
//        customsDeclarationMap.put("non_delivery_option", "RETURN");
//        customsDeclarationMap.put("certify", true);
//        customsDeclarationMap.put("certify_signer", "Simon Kreuz");
//        customsDeclarationMap.put("items", customsItemMap);
//        String param = JSONUtil.toJsonStr(customsDeclarationMap);

//        log.info("==========shippo 海关申报单请求开始================请求参数:[{}]", param);
//        String responseData = sendPostRequest(apiPrefix + ShippoApiConstants.CUSTOMS_DECLARATIONS,param);
//        log.info("==========shippo 海关申报单请求结束================响应结果:[{}]", responseData);
//        return responseData;
        return null;
    }

    public String sendPostRequest(String sendUrl, String param) {
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, param);
        Request request = new Request.Builder()
                .url(sendUrl)
                .addHeader("Content-Type", "application/json")
                .header("Authorization", ShippoApiConstants.TOKEN_TYPE + getApiToken())
                .method("POST", body)
                .build();
        return getResponse(client, request);
    }

    public String sendGetRequest(String sendUrl) {
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        Request request = new Request.Builder()
                .header("Authorization", ShippoApiConstants.TOKEN_TYPE + getApiToken())
                .url(sendUrl).build();
        return getResponse(client, request);
    }

    private String getResponse(OkHttpClient client, Request request) {
        // 只有主动抛出 needRetryException才会重试  其他任何异常都不会重试
        // 发送请求并获取响应
        Retryer build = retryBuilder.build();
        Callable<String> getTokeCall = ()->{
            Response response = client.newCall(request).execute();
            String responseBody = "";
            if (response.isSuccessful()) {
                // 处理返回的数据
                if (ObjectUtil.isNotNull(response.body())) {
                    // response.body().string取一次后 再次取会异常 这里不反悔response直接返回 string
                    responseBody = response.body().string();
                }
            } else {
                log.info("未请求成功 响应码:{}", response.code());
            }
            return responseBody;
        };
        String responseBody = null;
        try {
            responseBody = (String) build.call(getTokeCall);
        } catch (ExecutionException | RetryException e) {
            Asserts.fail("接口请求失败");
        }
        return responseBody;
    }

    public String getApiToken() {
        String[] activeProfiles = environment.getActiveProfiles();
        String activeProfile = "";
        if (ObjectUtil.isNotEmpty(activeProfiles)) {
            activeProfile = environment.getActiveProfiles()[0];
        }
        String apiToken = null;
        if (activeProfile.equals(EnvironmentConstants.PROD)) {
            apiToken = prodToken;
        } else {
            apiToken = testToken;
        }
        log.info("shippo当前环境:[{}], 请求token:[{}]", activeProfile, apiToken);
        return apiToken;
    }
}
